/*
 * This file is part of algowala.
 *
 * algowala is copyright (c) 2012 Jagannathan Sampath <algowala@jagernot.com>
 *
 * algowala is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * algowala is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with algowala.  If not, see <http://www.gnu.org/licenses/>.
 *
*/

#ifndef _CONSOLE
#define _CONSOLE

#define eol console::EOL
#define cll console::CLL
#define tab "  "

#include "algo_gl.h"
#include "color.h"
#include "widget.h"
#include "tokenizer.h"

#include <vector>
#include <string>
#include <sstream>

struct mesg {

  std::string text; // text
  color clr; // color

  mesg (const std::string& t, const color& c) : text(t), clr(c) {}
  mesg (const std::string& t) : text(t), clr (1, 1, 1) {}
  mesg () : clr (1, 1, 1) {}

};

template <class T> struct pusher {
  virtual T& operator<< (const std::string& s)=0;
  virtual T& operator<< (char c)=0;
};

template<class T> void into_lines (const std::string& str, pusher<T>& push) {

  static tokenizer tz;
  static const std::string newline = "\n";
  static const char endln = '\n';

  if (str.length()) {
    tz.set (str, newline);
    std::string ln;
    while (1) {
      std::string ln; tz >> ln;
      if (ln == "") break; else { push << ln << endln; }
    }
  }
}

struct console : widget, pusher<console> {

  // colors of text
  static const color yellow;
  static const color green;
  static const color red;
  static const color cyan;
  static const color gray;

  static const char EOL = '\n'; // end of last mesg
  static const char CLL = '\b'; // clear last mesg

  // console text is a bunch of lines
  //
  static const int GUTTER = 5; // number of lines
  int nlines; // number of lines in console
  int startl, lines_per_screen; // start line of display and lines per screen
  std::vector<mesg> lines;
  void add_line (const mesg& ln);
  void clear (); // clear all lines on console

  mesg cur_line; // currently edited line
  color clr; // its color

  console ();

  // operators for appending values to console
  console& operator() (const std::string& cmd);
  console& operator<< (unsigned int i);
  console& operator<< (unsigned long i);
  console& operator<< (unsigned long long i);
  console& operator<< (int i);
  console& operator<< (const std::string& s);
  console& operator<< (float f);
  console& operator<< (double d);
  console& operator<< (char c);
  console& operator<< (const color& d);

  void up (int i); // scroll up by i lines
  void down (int i); // scroll down
  void pgdn (); // page down
  void pgup (); // page up
  void home (); // scroll to show 1st line
  void end (); // scroll to show last line

  void last (); // ensures last mesg is always displayed
  void del (); // del one character from currently edited line

  // visual
  //

  std::string ps1; // console prompt
  int rollup; // roll up console? ie show last line only?
  void roll_unroll (int what);

  int char_width;
  int line_height;

  box<int> win;
  void set_window (const box<int>& w);

  int startx, starty; // bottom (left), top(left)

  int curs_loc;
  int curs_locx;
  
  void calc_visual_params ();
  void draw ();

  // input
  //

  int handle_input ();

  // commands
  //
  int command_mode; // in command mode?
  mesg cmd_line; // command text
  void toggle_command_mode ();
  
  std::vector<std::string> history; // command history
  int hid;

};

template <class T> inline console& operator<< (console& c, const box<T>& b) {
  c << b.left << ' ' << b.bottom << ' ' << b.right << ' ' << b.top;
  return c;
}

extern console cons;
#endif
